package Concurrency2.Chapter02_InnerLockPrinciple.P05_WaitNotify;

import java.util.ArrayList;
import java.util.List;

/**
 * 1, 集合容器
 * 2, 主要功能: 添加, 获取
 */
public class DataBuffer<T> {
    private List<T> container;
    private Integer CAPACITY = 10;
    private Integer capacity = CAPACITY;
    private Object notFullLock = new Object();  // 用于控制生产者wait和唤醒生产者
    private Object notEmptyLock = new Object(); // 用于控制消费者线程的运行和暂停
    private Object mainLock = new Object();     // 用于控制容器的锁

    public DataBuffer(Integer capacity) {
        this.capacity = capacity == null ? this.capacity : capacity;
        this.container = new ArrayList<>(this.capacity);
    }

    /**
     * 添加功能
     * @param data 数据
     */
    public void add(T data) {
        // 如果容积已经满了, 让生产者等待
        while (this.container.size() >= this.capacity) {
            synchronized (notFullLock) {
                try {
                    notFullLock.wait(); // 生产者等待
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        // TODO 生产者启动 - 有一个问题: 在跳出上一个同步代码块之后, 到这里, 容积是否被其它生产线程更新了数据
        synchronized (mainLock) {
            this.container.add(data);
        }
        // 唤醒消费者
        synchronized (notEmptyLock) {
            notEmptyLock.notify();
        }
    }

    public T fetch() {
        while (this.container.size() <= 0) {
            try {
                notEmptyLock.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        T t = null;
        synchronized (mainLock) {
            t = this.container.remove(0);
        }
        synchronized (notFullLock) {
            notFullLock.notify();
        }
        return t;
    }
}
